home *** CD-ROM | disk | FTP | other *** search
- /*
- Generic Convex Polygon Scan Conversion and Clipping
- by Paul Heckbert
- from "Graphics Gems", Academic Press, 1990
- */
-
- /*
- * poly_scan.c: point-sampled scan conversion of convex polygons
- *
- * Paul Heckbert 1985, Dec 1989
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "poly.h"
-
- /*
- * poly_scan: Scan convert a polygon, calling pixelproc at
- * each pixel with an interpolated Poly_vert structure.
- * Polygon can be clockwise or ccw.
- * Polygon is clipped in 2-D to win, the screen space window.
- *
- * Scan conversion is done on the basis of Poly_vert fields sx and sy.
- * These two must always be interpolated, and only they have
- * special meaning to this code; any other fields are
- * blindly interpolated regardless of their semantics.
- *
- * The pixelproc subroutine takes the arguments:
- *
- * pixelproc(x, y, point)
- * int x, y;
- * Poly_vert *point;
- *
- * All the fields of point indicated by p->mask will be
- * valid inside pixelproc except sx and sy.
- * If they were computed, they would have values
- * sx=x+.5 and sy=y+.5, since sampling is done at pixel centers.
- */
-
- void poly_scan(p, win, pixelproc)
- register Poly *p; /* polygon */
- Window *win; /* 2-D screen space clipping window */
- void (*pixelproc)(); /* procedure called at each pixel */
- {
- register int i, li, ri, y, ly, ry, top, rem, mask;
- double ymin;
- Poly_vert l, r, dl, dr;
-
- if (p->n>POLY_NMAX) {
- fprintf(stderr, "poly_scan: too many vertices: %d\n", p->n);
- return;
- }
-
-
- ymin = HUGE;
- for (i=0; i<p->n; i++) /* find top vertex (y points down) */
- if (p->vert[i].sy < ymin) {
- ymin = p->vert[i].sy;
- top = i;
- }
-
- li = ri = top; /* left and right vertex indices */
- rem = p->n; /* number of vertices remaining */
- y = ceil(ymin-.5); /* current scan line */
- ly = ry = y-1; /* lower end of left & right edges */
- mask = p->mask & ~POLY_MASK(sy); /* stop interpolating screen y */
-
- while (rem>0) { /* scan in y, activating new edges on left & */ /* right as scan line passes over new vertices */
-
- while (ly<=y && rem>0) { /* advance left edge? */
- rem--;
- i = li-1; /* step ccw down left side */
- if (i<0) i = p->n-1;
- incrementalize_y(&p->vert[li], &p->vert[i], &l,
- &dl, y, mask);
- ly = floor(p->vert[i].sy+.5);
- li = i;
- }
- while (ry<=y && rem>0) { /* advance right edge? */
- rem--;
- i = ri+1; /* step cw down right edge */
- if (i>=p->n) i = 0;
- incrementalize_y(&p->vert[ri], &p->vert[i], &r,
- &dr, y, mask);
- ry = floor(p->vert[i].sy+.5);
- ri = i;
- }
-
- while (y<ly && y<ry) {
- /* do scanlines till end of l or r edge */
- if (y>=win->y0 && y<=win->y1)
- if (l.sx<=r.sx) scanline(y, &l, &r, win, pixelproc, mask);
- else scanline(y, &r, &l, win, pixelproc, mask);
- y++;
- increment(&l, &dl, mask);
- increment(&r, &dr, mask);
- }
- }
- }
-
-
- /* scanline: output scanline by sampling polygon at Y=y+.5 */
-
- static scanline(y, l, r, win, pixelproc, mask)
- int y, mask;
- Poly_vert *l, *r;
- Window *win;
- void (*pixelproc)();
- {
- int x, lx, rx;
- Poly_vert p, dp;
-
- mask &= ~POLY_MASK(sx); /* stop interpolating screen x */
- lx = ceil(l->sx-.5);
- if (lx<win->x0) lx = win->x0;
- rx = floor(r->sx-.5);
- if (rx>win->x1) rx = win->x1;
- if (lx>rx) return;
- incrementalize_x(l, r, &p, &dp, lx, mask);
- for (x=lx; x<=rx; x++) { /* scan in x, generating pixels */
- (*pixelproc)(x, y, &p);
- increment(&p, &dp, mask);
- }
- }
-
- /*
- * incrementalize_y: put intersection of line Y=y+.5 with edge
- * between points p1 and p2 in p, put change with respect to y in dp
- */
-
- static incrementalize_y(p1, p2, p, dp, y, mask)
- register double *p1, *p2, *p, *dp;
- register int mask;
- int y;
- {
- double dy, frac;
-
- dy = ((Poly_vert *)p2)->sy - ((Poly_vert *)p1)->sy;
- if (dy==0.) dy = 1.;
- frac = y+.5 - ((Poly_vert *)p1)->sy;
-
- for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
- if (mask&1) {
- *dp = (*p2-*p1)/dy;
- *p = *p1+*dp*frac;
- }
- }
-
-
- /*
- * incrementalize_x: put intersection of line X=x+.5 with
- * edge between points p1 and p2 in p,
- * put change with respect to x in dp
- */
-
- static incrementalize_x(p1, p2, p, dp, x, mask)
- register double *p1, *p2, *p, *dp;
- register int mask;
- int x;
- {
- double dx, frac;
-
- dx = ((Poly_vert *)p2)->sx - ((Poly_vert *)p1)->sx;
- if (dx==0.) dx = 1.;
- frac = x+.5 - ((Poly_vert *)p1)->sx;
-
- for (; mask!=0; mask>>=1, p1++, p2++, p++, dp++)
- if (mask&1) {
- *dp = (*p2-*p1)/dx;
- *p = *p1+*dp*frac;
- }
- }
-
- static increment(p, dp, mask)
- register double *p, *dp;
- register int mask;
- {
- for (; mask!=0; mask>>=1, p++, dp++)
- if (mask&1)
- *p += *dp;
- }
-